/*
 * Copyright (c) 2020 - present, Inspur Genersoft Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package io.iec.edp.caf.commons.caching;

import io.iec.edp.caf.commons.caching.proxy.JedisClusterProxy;
import io.iec.edp.caf.commons.caching.proxy.JedisPoolProxy;
import io.iec.edp.caf.commons.caching.proxy.JedisProxy;
import io.iec.edp.caf.commons.caching.proxy.JedisSentinelProxy;
import io.iec.edp.caf.commons.layeringcache.properties.CacheSetting;
import io.iec.edp.caf.commons.layeringcache.properties.JedisPoolConfigProperties;
import io.iec.edp.caf.commons.layeringcache.support.RedisServerMode;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.connection.RedisNode;
import org.springframework.util.Assert;
import redis.clients.jedis.HostAndPort;
import redis.clients.jedis.JedisPoolConfig;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * JedisPool工具类
 *
 * @author wangyandong
 */
@Deprecated
//todo 被CacheFactory依赖
public class JedisPoolManager implements AutoCloseable {
    @Autowired
    private JedisPoolConfigProperties configuration;
    private Map<String, JedisProxy> pools;
    private Lock lock;

    /**
     * 私有构造函数
     */
    public JedisPoolManager() {
        this.pools = new HashMap<>();
        this.lock = new ReentrantLock();
    }

//    public static JedisPoolManager getCurrent(){
//        if(current==null)
//            current = new JedisPoolManager();
//        return current;
//    }

    /**
     * 获得jedisPool资源的方法
     */
    public JedisProxy getJedisProxy(CacheSetting data) {
        String key = data.getMode() == RedisServerMode.STANDALONE ?
                String.format("%s-%s-%s", data.getHost(), data.getPort(), data.getDatabase()) :
                String.format("%s-%s", data.getMode(), data.getClusterNodes());
        if (!this.pools.containsKey(key)) {
            lock.lock();
            try {
                if (!this.pools.containsKey(key)) {
                    JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
                    jedisPoolConfig.setMaxTotal(configuration.getMaxTotal());
                    jedisPoolConfig.setMaxIdle(configuration.getMaxIdle());
                    jedisPoolConfig.setMaxWaitMillis(configuration.getMaxWaitMillis());
                    jedisPoolConfig.setMinIdle(configuration.getMinIdle());
                    Set<HostAndPort> hostAndPortSet = new HashSet<>();
                    //读取配置
                    JedisProxy jedisProxy;
                    switch (data.getMode()) {
                        case STANDALONE:
                            jedisProxy = new JedisPoolProxy(jedisPoolConfig, data.getHost(), data.getPort(), 10000, data.getPassword(), data.getDatabase());
                            break;
                        case CLUSTER:
                            Assert.notEmpty(data.getClusterNodes(), "Please ensure set at least one cluster node.");
                            for (RedisNode redisNode : data.getClusterNodes()) {
                                hostAndPortSet.add(new HostAndPort(redisNode.getHost(), redisNode.getPort()));
                            }

                            jedisProxy = new JedisClusterProxy(jedisPoolConfig, hostAndPortSet, data.getMaxRedirects(), data.getPassword());
                            break;
                        case SENTINEL:
                            for (RedisNode redisNode : data.getClusterNodes()) {
                                hostAndPortSet.add(new HostAndPort(redisNode.getHost(), redisNode.getPort()));
                            }

                            jedisProxy = new JedisSentinelProxy(jedisPoolConfig, hostAndPortSet, data.getMaster(), data.getPassword());
                            break;
                        default:
                            throw new RuntimeException("not support this mode");
                    }

                    this.pools.put(key, jedisProxy);
                }
            } finally {
                lock.unlock();
            }
        }
        return this.pools.get(key);
    }

    @Override
    public void close() throws Exception {
        if (this.pools != null && this.pools.size() > 0) {
            for (JedisProxy proxy : this.pools.values()) {
                if (proxy != null && !proxy.isClosed())
                    proxy.close();
            }
        }
    }
}
